<?php

namespace App\Repository;

use App\Common\Libs\Pagination;
use App\Consts\ExceptionCodeConst;
use App\Consts\MessageConst;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Validator;

class BaseRepository extends Repository
{

    /** @var null $validator */
    public $validator = null;

    /** @var Model $model */
    protected $model = null;

    /**
     * get pagination
     * @param array $paginationParams
     * @return Pagination
     */
    public function getPagination($paginationParams = [])
    {
        return (new Pagination())->getPagination($paginationParams);
    }

    /**
     * set pagination
     * @param Builder $provider
     * @param array|Pagination $paginationParams
     * @return Builder
     */
    public function setPagination(Builder $provider, $paginationParams = [])
    {
        if ($paginationParams instanceof  Pagination) {
            $pagination = $paginationParams;
            $pagination->page--;
        } else {
            $pagination = $this->getPagination($paginationParams);
        }

        $offset = $pagination->page * $pagination->pageSize;

        return $provider->offset($offset)->take($pagination->pageSize);
    }

    /**
     * validate data
     * @param array $data
     * @param array $rule
     * @param array $message
     * @return \Illuminate\Http\JsonResponse|bool
     */
    public function validate($data = [], $rule = [], $message = [])
    {
        $this->validator = Validator::make($data, $rule, $message);
        if ($this->validator->fails()) {
            return apiShutdown($this->validator->errors()->first(), ExceptionCodeConst::ILLEGAL_PARAMETER);
        }
        return true;
    }

    /**
     * 错误中断返回
     * @param $message
     * @param int $code
     */
    public function throwError($message, $code = ExceptionCodeConst::CODE_FAIL)
    {
        return apiShutdown($message, $code);
    }

    /**
     * bound query
     * @param $params
     * @param mixed $field
     * @return Builder|Model
     */
    public function boundQuery($params, $field = ['*'])
    {
        $inWhere = getVal($params, 'in', []);
        $orWhere = getVal($params, 'or', []);
        $strWhere = getVal($params, 'str', []);
        $query = $this->model;
        if ($strWhere) {
            $query = $query->whereRaw($strWhere);
            unset($params['str']);
        }
        if ($inWhere) {
            foreach ($inWhere as $key => $val) {
                $query = $query->whereIn($key, $val);
            }
            unset($params['in']);
        }
        if ($orWhere) {
            foreach ($orWhere as $key => $val) {
                $query = $query->orWhere($key, $val);
            }
            unset($params['or']);
        }
        if (!empty($params)) {
            $query = $query->where($params);
        }
        if (false !== $field) {
            $query = $query->select($field);
        }
        return $query;
    }


    /**
     * 获取列表
     * @param $where
     * @param int $offset
     * @param int $limit
     * @param array $field
     * @param array $sort
     * @param array $group
     * @return array
     */
    public function getListByWhere($where, $offset = 0, $limit = 0, $field = ['*'], $sort = [], $group = [])
    {
        $limit = $limit ?: 10;
        $sortField = getVal($sort, 'field', 'id');
        $sortDesc = getVal($sort, 'desc', 'desc');
        $list = $this->boundQuery($where, $field)
            ->groupBy($group)
            ->orderBy($sortField, $sortDesc)
            ->offset($offset)
            ->limit($limit)
            ->get();
        return $list ? $list->toArray() : [];
    }

    /**
     * 获取总数
     * @param $where
     * @return int
     */
    public function getCountByWhere($where)
    {
        $count = $this->boundQuery($where, false)
            ->count();
        return $count;
    }

    /**
     * 获取信息
     * @param $id
     * @param array $field
     * @return array
     */
    public function getInfoById($id, $field = ['*'])
    {
        $info = $this->model
            ->where('id', $id)
            ->where('is_deleted', MessageConst::IS_DELETED_NO)
            ->select($field)
            ->first();
        return $info ? $info->toArray() : [];
    }

    /**
     * 获取信息 - 根据条件
     * @param $where
     * @param array $field
     * @return array
     */
    public function getInfoByWhere($where, $field = ['*'])
    {
        $info = $this->boundQuery($where, $field)
            ->where('is_deleted', MessageConst::IS_DELETED_NO)
            ->first();
        return $info ? $info->toArray() : [];
    }

    /**
     * 更新信息
     * @param $id
     * @param $data
     * @return int
     */
    public function updateInfoById($id, $data)
    {
        $data['update_time'] = !empty($data['update_time']) ? $data['update_time'] : time();
        return $this->model
            ->where('id', $id)
            ->update($data);
    }

    /**
     * 更新信息 - 根据条件
     * @param $where
     * @param $data
     * @return int
     */
    public function updateInfoByWhere($where, $data)
    {
        $data['update_time'] = !empty($data['update_time']) ? $data['update_time'] : time();
        return $this->boundQuery($where, false)
            ->update($data);
    }

    /**
     * 添加单条数据
     * @param $data
     * @param string $method
     * @return mixed
     */
    public function add($data, $method = '')
    {
        $method = $method ? : 'insertGetId';
        $data['create_time'] = !empty($data['create_time']) ? $data['create_time'] : time();
        $data['update_time'] = !empty($data['update_time']) ? $data['update_time'] : time();
        return $this->model->$method($data);
    }

    /**
     * alias for add
     * @param $data
     * @return mixed
     */
    public function insert($data)
    {
        return $this->add($data);
    }

    /**
     * 删除信息
     * @param $id
     * @param bool $realDelete
     * @return bool|int|null
     * @throws \Exception
     */
    public function deleteInfoById($id, $realDelete = false)
    {
        if ($realDelete) {
            $res = $this->model
                ->where('id', $id)
                ->delete();
        } else {
            $res = $this->updateInfoById($id, ['is_deleted' => MessageConst::IS_DELETED_YES]);
        }
        return $res;
    }

    /**
     * 删除信息 - 根据条件
     * @param $where
     * @param bool $realDelete
     * @return bool|int|null
     * @throws \Exception
     */
    public function deleteInfoByWhere($where, $realDelete = false)
    {
        if ($realDelete) {
            $res = $this->boundQuery($where, false)
                ->delete();
        } else {
            $res = $this->updateInfoByWhere($where, ['is_deleted' => MessageConst::IS_DELETED_YES]);
        }
        return $res;
    }


}
